package com.itcanteen.medical.patient.util;

import org.I0Itec.zkclient.IZkDataListener;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CountDownLatch;

public class HighPerformanceZkLock extends AbstractLock {

    //一个节点路径
    private static final String PATH = "/highPerformnace_zklock";

    //当前节点
    private String currentPath;
    //前一个节点
    private String beforePath;

    //相当于一个程序计数器，用来保证线程的唯一性，0是没有，>0有线程，执行完毕后-1
    private CountDownLatch countDownLatch = null;

    public HighPerformanceZkLock(){
        //如果不存在这个节点,则创建持久节点
        if (!zkClient.exists(PATH)){
            zkClient.createPersistent(PATH);
        }
    }
    //释放锁
    @Override
    public void releaseLock() {
        if (null!=zkClient){
            System.out.println("---------释放锁-------");
            zkClient.delete(currentPath);
            zkClient.close();
        }
    }

    @Override
    public boolean tryLock(String lock) {
        //判断currentPath是否为空，为空则进行加锁
        if (null==currentPath||" ".equals(currentPath)){
            //在path下创建一个临时顺序节点
            currentPath = zkClient.createEphemeralSequential(PATH+"/",lock);
        }

        //获取所有的临时节点，并排序
        List<String> children = zkClient.getChildren(PATH);
        //使用Collections。sort进行排序
        Collections.sort(children);

        //判断是否是排名第一的节点，如果不是就获取前面的节点，然后给beforePath,
        //是第一个返回true，给AbstractLock中的getLock
        if (currentPath.equals(PATH+"/"+children.get(0))){
            return true;
        }else {
            //获取长度
            int length = PATH.length();
            //查找当前的下标
            int wz = Collections.binarySearch(children, currentPath.substring(length+1));
            //获取当前下标的前一个值
            beforePath = PATH+"/"+children.get(wz-1);
        }
        return false;
    }


    //等待加锁
    @Override
    public void waitLock() {

        //监听加锁的值
        IZkDataListener iZkDataListener = new IZkDataListener() {

            //监听头部的信息
            @Override
            public void handleDataChange(String s, Object o) throws Exception {

            }

            @Override
            public void handleDataDeleted(String s) throws Exception {
                if (null!=countDownLatch){
                    countDownLatch.countDown();
                }
            }
        };

        //监听前一个节点的变化
        zkClient.subscribeDataChanges(beforePath, iZkDataListener);

        if (zkClient.exists(beforePath)) {
            //计数器为1
            countDownLatch = new CountDownLatch(1);
            try {
                //保证这个线程执行完毕，相当去守护线程
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        zkClient.unsubscribeDataChanges(beforePath,iZkDataListener);
    }
}
